package com.witmore.neutron.ai.cognitive.service;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 会话次数扣减锁策略服务
 * 提供不同粒度的锁机制
 * Author: 豆子高
 * Date: 2025/1/15
 */
@Slf4j
@Service
public class SessionUsageLockStrategy {

    @Autowired
    private DistributedLock distributedLock;

    /**
     * 锁类型枚举
     */
    @Getter
    public enum LockType {
        USER_DEDUCT("user_session_deduct", 3, 10),           // 用户扣减锁，等待3秒，持有10秒
        USER_CHECK("user_session_check", 1, 3),             // 用户检查锁，等待1秒，持有3秒
        USER_QUERY("user_session_query", 0, 2),             // 用户查询锁，不等待，持有2秒
        BATCH_OPERATION("batch_session_operation", 5, 30);   // 批量操作锁，等待5秒，持有30秒

        private final String prefix;
        private final long waitTime;
        private final long leaseTime;

        LockType(String prefix, long waitTime, long leaseTime) {
            this.prefix = prefix;
            this.waitTime = waitTime;
            this.leaseTime = leaseTime;
        }

    }

    /**
     * 基于用户ID构建锁键
     *
     * @param lockType 锁类型
     * @param userId 用户ID
     * @return 锁键
     */
    public String buildUserLockKey(LockType lockType, Integer userId) {
        return lockType.getPrefix() + ":" + userId;
    }

    /**
     * 基于用户ID和会话ID构建锁键（更细粒度）
     *
     * @param lockType 锁类型
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @return 锁键
     */
    public String buildSessionLockKey(LockType lockType, Integer userId, String sessionId) {
        return lockType.getPrefix() + ":" + userId + ":" + sessionId;
    }

    /**
     * 执行带用户级别锁的操作
     *
     * @param lockType 锁类型
     * @param userId 用户ID
     * @param task 要执行的任务
     * @param <T> 返回值类型
     * @return 执行结果
     * @throws Exception 执行异常
     */
    public <T> T executeWithUserLock(LockType lockType, Integer userId, DistributedLock.LockTask<T> task) throws Exception {
        String lockKey = buildUserLockKey(lockType, userId);
        return distributedLock.executeWithLock(
            lockKey,
            lockType.getWaitTime(),
            lockType.getLeaseTime(),
            TimeUnit.SECONDS,
            task
        );
    }

    /**
     * 执行带会话级别锁的操作
     *
     * @param lockType 锁类型
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @param task 要执行的任务
     * @param <T> 返回值类型
     * @return 执行结果
     * @throws Exception 执行异常
     */
    public <T> T executeWithSessionLock(LockType lockType, Integer userId, String sessionId, DistributedLock.LockTask<T> task) throws Exception {
        String lockKey = buildSessionLockKey(lockType, userId, sessionId);
        return distributedLock.executeWithLock(
            lockKey,
            lockType.getWaitTime(),
            lockType.getLeaseTime(),
            TimeUnit.SECONDS,
            task
        );
    }

    /**
     * 尝试获取用户级别的锁
     *
     * @param lockType 锁类型
     * @param userId 用户ID
     * @return 是否获取成功
     */
    public boolean tryUserLock(LockType lockType, Integer userId) {
        String lockKey = buildUserLockKey(lockType, userId);
        return distributedLock.tryLock(
            lockKey,
            lockType.getWaitTime(),
            lockType.getLeaseTime(),
            TimeUnit.SECONDS
        );
    }

    /**
     * 释放用户级别的锁
     *
     * @param lockType 锁类型
     * @param userId 用户ID
     */
    public void unlockUser(LockType lockType, Integer userId) {
        String lockKey = buildUserLockKey(lockType, userId);
        distributedLock.unlock(lockKey);
    }

    /**
     * 智能选择锁策略
     * 根据业务场景自动选择合适的锁粒度和超时配置
     *
     * @param operation 操作类型
     * @param userId 用户ID
     * @param sessionId 会话ID（可选）
     * @param task 要执行的任务
     * @param <T> 返回值类型
     * @return 执行结果
     * @throws Exception 执行异常
     */
    public <T> T executeWithSmartLock(String operation, Integer userId, String sessionId, DistributedLock.LockTask<T> task) throws Exception {
        LockType lockType;
        boolean useSessionLevel = false;

        switch (operation.toLowerCase()) {
            case "deduct":
            case "扣减":
                lockType = LockType.USER_DEDUCT;
                break;
            case "check":
            case "检查":
                lockType = LockType.USER_CHECK;
                break;
            case "query":
            case "查询":
                lockType = LockType.USER_QUERY;
                break;
            case "batch":
            case "批量":
                lockType = LockType.BATCH_OPERATION;
                break;
            default:
                lockType = LockType.USER_CHECK; // 默认使用检查锁
                log.warn("未知操作类型: {}, 使用默认锁策略", operation);
        }

        // 对于高频操作，可以考虑使用会话级锁减少冲突
        if (sessionId != null && (operation.equals("query") || operation.equals("查询"))) {
            useSessionLevel = true;
        }

        if (useSessionLevel) {
            return executeWithSessionLock(lockType, userId, sessionId, task);
        } else {
            return executeWithUserLock(lockType, userId, task);
        }
    }
}
